package com.cctc.juc.demo.Bitc.Fjuctools.ASemaphore;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class SemaphoreDemo {

    /**
     * 线程间通信方式之使用 Semaphore 信号量：同一时刻只允许固定数量的任务线程并发执行。
     * Semaphone [信号量] 是一个常用的线程同步工具，其功能相当于一个许可管理器，每个时刻只能允许获取固定数量许可证的线程并发执行，经常用来限制并发执行线程的数量，例如限流等。
     * 核心方法：
     * - public Semaphore(int permits);
     * - public void acquire() throws InterruptedException;
     * - public void acquire(int permits) throws InterruptedException;
     * - public void release();
     * - public void release(int permits);
     * 使用步骤：
     * 1）调用构造器，创建信号量，指定 Semaphone 的并发许可证数量，比如 5;
     * 2）每当一个子任务线程执行前，调用 Semaphone.acquire() 方法，获取一个许可证，执行完成后，调用 Semaphone.release() 释放许可证。
     * 说明：由于 Semaphone 并发许可总量是固定的，因此每个时刻只能允许获取到许可证的固定数量线程并发执行。
     */
    private static final AtomicInteger index = new AtomicInteger(0);

    public static void main(String[] args) {
        final Semaphore semaphore = new Semaphore(2);
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            executorService.execute(() -> {
                try {
                    // 当前执行线程，获取许可证，获取到，继续向下执行，获取不到，自我等待。
                    semaphore.acquire();

                    // [并发] 操作共享资源。
                    System.out.println("线程 {" + Thread.currentThread().getName() + "} 获取了一个许可，处理服务号 -> " + index.incrementAndGet());
                    TimeUnit.SECONDS.sleep(1);

                    // 当前执行线程，释放许可证，唤醒等待线程。
                    semaphore.release();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });
        }
        executorService.shutdown();
    }

}
